//-----------------------------------------------------------------------
// <copyright file="CheckComponentInstalled.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Simon Ransom</author>
// <email></email>
// <date>2004-03-23</date>
// <summary> Check that a windows component is installed such as IIS</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks
{
    using System;
    using System.Text;
    using System.Xml;
    using System.Globalization;
    using System.IO;
    using Microsoft.Build.Framework;
    using Microsoft.Sdc.Tasks.Configuration.InstalledProducts;

    /// <summary>
    /// Check that a windows component is installed such as IIS
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[
    /// <CheckComponentInstalled Ids="ids" IdComparisonOperators="idsComparisonOperators" UnaryOperators="unaryOperators" 
    ///                          InstalledComponentsXml="installedComponentsXml">
    ///     <Output TaskParameter="Summary" ItemName="SummaryItem" />
    ///     <Output TaskParameter="Success" ItemName="SuccessItem" />
    /// </CheckComponentInstalled>
    /// ]]></code>
    /// <para>where:</para>
    /// <para><i>ids (Required)</i></para>
    /// <para>Ids of the components to check for as found in:
    /// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OC Manager\Subcomponents
    /// For example, "iis_www"
    /// </para>
    /// <para><i>idsComparisonOperators (Required)</i></para>
    /// <para>Name comparison operators for each of the component ids speciifed in <i>ids</i>. Can be any of:
    ///         "Equals",
    ///         "Contains"
    ///         "LessThan"
    ///         "GreaterThan"
    ///         "LessThanOrEquals"
    ///         "GreaterThanOrEquals"
    /// </para>
    /// <para><i>unaryOperators (Required)</i></para>
    /// <para>Unary operators for the respective <i>idsComparisonOperators</i>, allowing (for example) "Not Equals" to be created. Can be "None" or "Not".</para>
    /// <para><i>installedComponentsXml (Required)</i></para>
    /// <para>A list of the components installed on the local machine. This will typically be generated by the <seealso cref="Microsoft.Sdc.Tasks.GetInstalledComponents">GetInstalledComponents</seealso> task</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <CheckComponentInstalled
    ///             Ids="aspnet" IdComparisonOperators="Equals" UnaryOperators="None", InstalledComponentsXml="$(InstalledComponentsXmlItem)">
    ///                     <Output TaskParameter="Summary" ItemName="SummaryItem" />
    ///                     <Output TaskParameter="Success" ItemName="SuccessItem" />
    ///         </CheckComponentInstalled>
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class CheckComponentInstalled : TaskBase
    {
        private string summary;
        private bool success;
        private string[] ids;
        private string[] idsComparisonOperators;
        private string[] unaryOperators;
        private string installedComponentsXml;
        private bool suppressWarnings = false;

        /// <summary>
        /// Initializes a new instance of the CheckComponentInstalled class.
        /// </summary>
        public CheckComponentInstalled()
        {
        }

        /// <summary>
        /// Set to true in order to suppress warnings reported by this task 
        /// </summary>
        /// <value>true or false (defaults to false)</value>
        public bool SuppressWarnings
        {
            get
            {
                return this.suppressWarnings;
            }
            set
            {
                this.suppressWarnings = value;
            }
        }

        /// <summary>
        /// Textual summary of components found and components not found
        /// </summary>
        [Output]
        public string[] Summary
        {
            get
            {
                return new string[] { this.summary };
            }
        }

        /// <summary>
        /// Success of the checking after execution.
        /// </summary>
        [Output]
        public string[] Success
        {
            get
            {
                return new string[] { Convert.ToString(this.success, CultureInfo.InvariantCulture) };
            }
        }

        /// <summary>
        /// Ids of the components to check for as found in:
        /// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OC Manager\Subcomponents
        /// </summary>
        /// <example>iis_www</example>
        [Required]
        public string[] Ids
        {
            get
            {
                return this.ids;
            }

            set
            {
                this.ids = value;
            }
        }

        /// <summary>
        /// Name comparison operators taken from BinaryComparisonOperator enumeration.
        /// </summary>
        /// <seealso cref="Microsoft.Sdc.Tasks.Configuration.InstalledProducts.BinaryComparisonOperator"/>
        /// <value> Can be any of:
        ///         "Equals",
        ///         "Contains"
        ///         "LessThan"
        ///         "GreaterThan"
        ///         "LessThanOrEquals"
        ///         "GreaterThanOrEquals"
        /// </value>
        [Required]
        public string[] IdComparisonOperators
        {
            get
            {
                return this.idsComparisonOperators;
            }

            set
            {
                this.idsComparisonOperators = value;
            }
        }

        /// <summary>
        /// Unary operators taken from UnaryLogicalOperator enumeration.
        /// </summary>
        /// <example>Not or None</example>
        /// <seealso cref="Microsoft.Sdc.Tasks.Configuration.InstalledProducts.UnaryLogicalOperator"/>
        public string[] UnaryOperators
        {
            get
            {
                return this.unaryOperators;
            }

            set
            {
                this.unaryOperators = value;
            }
        }

        /// <summary>
        /// Generated by GetInstalledComponents task
        /// </summary>
        [Required]
        public string InstalledComponentsXml
        {
            get
            {
                return this.installedComponentsXml;
            }

            set
            {
                this.installedComponentsXml = value;
            }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            // Convert list of installed components to ComponentList
            InstalledComponentsManager mgr = new InstalledComponentsManager();
            ComponentList installedComponents = mgr.ConvertFromXml(this.installedComponentsXml);
            bool isSuccessful = true;

            // TODO: Validate array lengths 
            if ((this.ids.Length != this.IdComparisonOperators.Length) ||
                (this.idsComparisonOperators.Length != this.unaryOperators.Length))
            {
                throw new TaskException("InstalledProducts.PropertyMismatch");
            }

            StringBuilder summary = new StringBuilder();

            // Loop through each of the names of the required components testing for existence
            for (int i = 0; i < this.ids.Length; i++)
            {
                // Id Comparison
                BinaryComparisonOperator tempComparisonOperator =
                    ((this.idsComparisonOperators != null) && (this.idsComparisonOperators[i] != null) && (this.idsComparisonOperators[i].Length > 0)) ?
                    (BinaryComparisonOperator) Enum.Parse(typeof(BinaryComparisonOperator), this.idsComparisonOperators[i]) : BinaryComparisonOperator.Equals;

                // Negate?
                UnaryLogicalOperator unaryOp =
                    ((this.unaryOperators != null) && (this.unaryOperators[i] != null) && (this.unaryOperators[i].Length > 0)) ?
                    (UnaryLogicalOperator) Enum.Parse(typeof(UnaryLogicalOperator), this.unaryOperators[i]) : UnaryLogicalOperator.None;

                Criteria criteria = new Criteria();
                mgr.AddForAnd(
                    criteria,
                    new Criterion(
                    typeof(Component).GetProperty("Id"),
                    new StringComparisonChecker(tempComparisonOperator),
                    this.ids[i]));

                Component matchingComponent = mgr.GetMatchingInstalledComponent(criteria, installedComponents);
                if (matchingComponent != null)
                {
                    StringBuilder componentSummary = new StringBuilder();
                    componentSummary.Append("'");
                    componentSummary.Append(matchingComponent.Id);
                    componentSummary.Append("' (");
                    componentSummary.Append(matchingComponent.Description);
                    componentSummary.Append(") ");

                    if (unaryOp == UnaryLogicalOperator.Not)
                    {
                        isSuccessful = false;

                        summary.Append(String.Format(CultureInfo.InvariantCulture, TaskResources.GetString("InstalledProducts.BadProduct"), componentSummary));
                        summary.Append(" ");
                        Log.LogErrorFromResources("InstalledProducts.BadProduct", componentSummary);
                    }
                    else
                    {
                        summary.Append(String.Format(CultureInfo.InvariantCulture, TaskResources.GetString("InstalledProducts.RequiredProduct"), componentSummary));
                    }
                }
                else
                {
                    if (unaryOp == UnaryLogicalOperator.Not)
                    {
                        // Correctly did not match criteria
                        summary.Append(TaskResources.GetString("InstalledProducts.CorrectMatchFailed"));
                        summary.Append(" ");
                        summary.Append(criteria.ToString());
                    }
                    else
                    {
                        string errorMsg = String.Format(CultureInfo.InvariantCulture, TaskResources.GetString("InstalledProducts.NotFound"), criteria.ToString());
                        summary.Append(errorMsg);
                        if (suppressWarnings == false)
                        {
                            Log.LogErrorFromResources("InstalledProducts.NotFound", criteria.ToString());
                        }
                        isSuccessful = false;
                    }
                }

                summary.Append(Environment.NewLine);
            }
            this.summary = summary.ToString();
            this.success = isSuccessful;
        }
    }
}